/**
 * stageController
 *
 * @file 阶段控制器（模板模式）
 * */

/**
 * StageObjMaker - 阶段对象（模板模式-命令片段对象）
 *
 * @class
 * @extends Object
 * */
export const StageObjMaker = function (stageSign) {
    return {
        /**
         * stageSign - 阶段对象标识
         *
         * @type string
         * @memberOf StageObjMaker
         * */
        stageSign: stageSign,
        /**
         * stageHookQueue - 阶段对象钩子队列
         *
         * @type Array
         * @memberOf StageObjMaker
         * */
        stageHookQueue: [],
        /**
         * hook - 阶段对象钩子函数
         *
         * @function
         * @param { Function } hookPart - 钩子片段
         * @memberOf StageObjMaker
         * */
        hook: function (hookPart) {
            this.stageHookQueue.push(hookPart);
        },
        /**
         * execute - 执行阶段对象所有钩子片段
         *
         * @function
         * @memberOf StageObjMaker
         * */
        execute: function () {
            this.stageHookQueue.forEach(hookPartObj => {
                hookPartObj();
            });
        }
    }
}

/**
 * StageController - 阶段控制器
 *
 * @class
 * @extends Object
 * */
export const StageController = function () {
    return {
        /**
         * stageQueue - 阶段队列
         *
         * @type Object
         * @memberOf StageController
         * */
        stageQueue: {},
        /**
         * add - 添加阶段
         *
         * @function
         * @param { StageObjMaker } stageObj - 添加阶段
         * @param { number } [index = Object.keys(this.stageQueue).length] - 队列序号索引
         * @param { boolean } [strict = true] - 严格模式，默认开启, 开启则遇到重复阶段标识则报错，关闭则覆盖
         * @return { Object } 添加的阶段队列片段对象
         * @throws { RangeError } - 已存在指定标识阶段，请勿重复添加！
         * @memberOf StageController
         * */
        add: function (
            stageObj,
            index = Object.keys(this.stageQueue).length,
            strict = true
        ) {
            if (this.stageQueue[stageObj.stageSign] !== void 0) {
                if (strict) {
                    throw new RangeError('已存在指定阶段标识，请勿重复添加！');
                }

                index = this.stageQueue[stageObj.stageSign].index;
            }

            // 阶段队列片段对象
            const stageQueuePart = {
                stageSign: stageObj.stageSign,
                stageObj: stageObj,
                index: index
            }

            this.stageQueue[stageObj.stageSign] = stageQueuePart;

            return stageQueuePart;
        },
        /**
         * remove - 去除阶段
         *
         * @function
         * @param { string } stageSign - 阶段标识
         * @param { boolean } [strict = true] - 严格模式，默认开启, 开启时不存在标识阶段对象则抛出错误，关闭则忽略
         * @return { Object|undefined } 删除的阶段队列片段对象（若存在）或空（非严格模式未找到指定阶段队列片段对象）
         * @throws { ReferenceError } - 未找到指定标识阶段对象！
         * @memberOf StageController
         * */
        remove: function (stageSign, strict = true) {
            if (this.stageQueue[stageSign] !== void 0) {
                const removeStageObj = this.stageQueue[stageSign];

                // 遍历更新队列片段序号
                Object.keys(this.stageQueue).forEach(stageQueuePart => {
                    if (stageQueuePart.index > removeStageObj.index) {
                        stageQueuePart.index--;
                    }
                });

                delete this.stageQueue[stageSign];

                return removeStageObj;
            }

            if (strict) {
                throw new ReferenceError('未找到指定标识阶段对象！');
            }
        }
    }
}

export default {
    StageObjMaker,
    StageController
}
